﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using CloudShot.Editor;
using CloudShot.Properties;
using CloudShot.ViewModels;

namespace CloudShot.Controls
{
  public partial class FigurePropertiesControl : UserControl
  {
    private readonly List<IPropertiesControlGroup> _controlGroups = new List<IPropertiesControlGroup>();
    private readonly IDrawingCanvas _canvas;
    private PropertiesFormViewModel _viewModel;
    private VisiblePropertiesState _visibleProperties;

    public event EventHandler CloseRequest;

    public VisiblePropertiesState VisibleProperties
    {
      get { return _visibleProperties; }
      set
      {
        _visibleProperties = value;
        UpdateVisibility();
      }
    }

    public FigurePropertiesControl(IDrawingCanvas canvas, EditorTheme theme)
    {
      InitializeComponent();
      _canvas = canvas;

      //border colors
      borderColorSelector.ApplyPalettes(theme.BorderColors);

      //back colors
      backColorSelector.ApplyPalettes(theme.BackColors);

      //text colors
      textColorSelector.ApplyPalettes(theme.TextColors);

      //opacity
      var opacityGroup = new RadioButtonPropertyHandler<byte?>(m => m.BackgroundOpacity);
      opacityGroup.Add(opacity1Button, theme.BackgroundOpacity1);
      opacityGroup.Add(opacity2Button, theme.BackgroundOpacity2);
      opacityGroup.Add(opacity3Button, theme.BackgroundOpacity3);
      opacityGroup.Add(opacity4Button, theme.BackgroundOpacity4);

      //border width
      var borderWidthGroup = new BorderPropertyHandler<int?>(m => m.BorderWidth);
      borderWidthGroup.Add(borderWidth1Button, theme.BorderWidth1);
      borderWidthGroup.Add(borderWidth2Button, theme.BorderWidth2);
      borderWidthGroup.Add(borderWidth3Button, theme.BorderWidth3);
      borderWidthGroup.Add(borderWidth4Button, theme.BorderWidth4);

      //border style
      var borderStyleGroup = new RadioButtonPropertyHandler<LineType?>(m => m.LineType);
      borderStyleGroup.Add(noBorderButton, LineType.None);
      borderStyleGroup.Add(solidBorderButton, LineType.Solid);
      borderStyleGroup.Add(dashesBorderButton, LineType.Dash);
      borderStyleGroup.Add(dotsBorderButton, LineType.Dot);

      _controlGroups.AddRange(new IPropertiesControlGroup[]
      {
        borderStyleGroup,
        borderWidthGroup,
        opacityGroup,
        FillRadioButtonGroup(new BackColorPropertyHandler(theme.BackgroundOpacity3, theme.FigureColorSchemes), backColorSelector.ColorRadioButtons),
        FillRadioButtonGroup(new BorderPropertyHandler<Color?>(m=>m.BorderColor), borderColorSelector.ColorRadioButtons),
        FillRadioButtonGroup(new RadioButtonPropertyHandler<Color?>(p => p.TextColor), textColorSelector.ColorRadioButtons)
      });

      foreach (IPropertiesControlGroup propertiesControlGroup in _controlGroups)
      {
        propertiesControlGroup.CloseRequest += OnCloseRequest;
        propertiesControlGroup.PreviewRequest += OnPreviewRequest;
      }
    }

    public void SetViewModel(PropertiesFormViewModel viewModel)
    {
      _viewModel = viewModel;

      SuspendLayout();

      foreach (IPropertiesControlGroup propertiesControlGroup in _controlGroups)
      {
        propertiesControlGroup.SetViewModel(viewModel);
      }

      UpdateVisibility();
      ResumeLayout(true);
    }

    private static RadioButtonPropertyHandler<Color?> FillRadioButtonGroup(RadioButtonPropertyHandler<Color?> colorGroup, IEnumerable<ColorRadioButton> buttons)
    {
      //var colorGroup = new RadioButtonPropertyHandler<Color?>(propertySelector);

      foreach (var colorRadioButton in buttons)
      {
        colorGroup.Add(colorRadioButton, colorRadioButton.Color);
      }

      return colorGroup;
    }

    private void UpdateVisibility()
    {
      SuspendLayout();

      //update line style buttons when CanvasArrow(s) is selected
      bool isArrowPart = _viewModel != null && _viewModel.IsArrowPartVisible;

      noBorderButton.Visible = !isArrowPart;

      noBorderButton.Image = isArrowPart ? Resources.menu_line_no_border : Resources.menu_no_border;
      solidBorderButton.Image = isArrowPart ? Resources.menu_line_solid_border : Resources.menu_solid_border;
      dashesBorderButton.Image = isArrowPart ? Resources.menu_line_dashes_border : Resources.menu_dashes;
      dotsBorderButton.Image = isArrowPart ? Resources.menu_line_dotted_border : Resources.menu_dots;

      noBorderButton.Width = isArrowPart ? 56 : 42;
      solidBorderButton.Width = isArrowPart ? 56 : 42;
      dashesBorderButton.Width = isArrowPart ? 56 : 42;
      dotsBorderButton.Width = isArrowPart ? 56 : 42;

      if (isArrowPart && noBorderButton.Checked)
        solidBorderButton.Checked = true;

      //back color & opacity
      bool isBackColorPart = _visibleProperties == VisiblePropertiesState.Background && _viewModel != null && _viewModel.IsBackColorPartVisible;
      backColorSelector.Visible = isBackColorPart;
      opacityPanel.Visible = isBackColorPart;

      //border
      bool isBorderPart = _visibleProperties == VisiblePropertiesState.Border && _viewModel != null;
      borderColorSelector.Visible = isBorderPart;
      borderWidthPanel.Visible = isBorderPart;
      borderStylePanel.Visible = isBorderPart;

      //text
      bool isTextPart = _visibleProperties == VisiblePropertiesState.Text && _viewModel != null && _viewModel.IsTextPartVisible;
      textColorSelector.Visible = isTextPart;

      ResumeLayout(true);
    }

    private void InvokeCloseRequest()
    {
      EventHandler handler = CloseRequest;
      if (handler != null)
        handler(this, EventArgs.Empty);
    }

    #region Event Handlers

    private void OnPreviewRequest(object sender, EventArgs e)
    {
      _canvas.RefreshCanvas(((PropertiesFormViewModel)sender).GetBoundingBox());
    }

    private void OnCloseRequest(object sender, EventArgs e)
    {
      //this is for refreshing properties. To set opacity after setting BackColor
      foreach (IPropertiesControlGroup propertiesControlGroup in _controlGroups)
      {
        propertiesControlGroup.RefreshProperty();
      }

      InvokeCloseRequest();
    }

    #endregion

    #region Nested type: VisiblePropertiesState

    public enum VisiblePropertiesState
    {
      Border,
      Background,
      Text
    }

    #endregion
  }
}